package drds.plus.sql_process.optimizer.execute_plan_optimizer;

import drds.plus.common.jdbc.Parameters;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.ExecutePlan;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.dml.IPut;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.Join;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.MergeQuery;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.QueryWithIndex;

import java.util.Map;

/**
 * 防止死锁的thread 号选择器。 每层会独立指定一个thread进行执行。这样就算是A->B->A 也不会出现死锁的问题。
 * 出现死锁的主要原因是请求是blocking状态的，所以导致后面的流数据无法处理，死锁。
 * 如果要修复这个问题，必须将请求发送和请求回收处理，逻辑上分开。变成发送流和接受流。才能解决，目前的方案是权宜方案 不会改变结构
 */
public class ChooseThreadOptimizer implements ExecutePlanOptimizer {

    public ChooseThreadOptimizer() {
    }

    public ExecutePlan optimize(ExecutePlan executePlan, Parameters parameters, Map<String, Object> extraCmd) {
        if (extraCmd != null && extraCmd.get("initThread") != null) {
            this.allocThread(executePlan, (Integer) extraCmd.get("initThread"));
        } else {
            this.allocThread(executePlan, 0);
        }

        return executePlan;
    }

    private void allocThread(ExecutePlan executePlan, int i) {
        executePlan.setThreadNo(i);

        if (executePlan instanceof IPut) {
            if (((IPut) executePlan).getQuery() != null) {
                this.allocThread(((IPut) executePlan).getQuery(), i + 1);
            }

        } else if (executePlan instanceof QueryWithIndex) {
            if (((QueryWithIndex) executePlan).getSubQuery() != null) {
                this.allocThread(((QueryWithIndex) executePlan).getSubQuery(), i + 1);
            }

        } else if (executePlan instanceof MergeQuery) {
            for (ExecutePlan subExecutePlan : ((MergeQuery) executePlan).getExecutePlanList()) {
                this.allocThread(subExecutePlan, i + 1);
            }

        } else if (executePlan instanceof Join) {
            this.allocThread(((Join) executePlan).getLeftNode(), i + 1);
            this.allocThread(((Join) executePlan).getRightNode(), i + 1);
        }

    }

}
